﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;

namespace org.xisoft.game.utils.game.algorithms
{
    public abstract class AsyncAlphaBetaAlgorithm<Broad> : AiAlgorithm<Broad>
                 where Broad : ChessBoardBase
    {
        private readonly long MATE = long.MaxValue / 2;
        delegate void CallbackDelegate(MoveAction arg);
        public void AsyncSearch(ISynchronizeInvoke synchronizeInvoke, Broad broad, Action<MoveAction> doAfterMove)
        {
            AsyncSearch(synchronizeInvoke, broad, MaxDeep, doAfterMove);
        }
        public void AsyncSearch(ISynchronizeInvoke synchronizeInvoke, Broad broad, int depth, Action<MoveAction> doAfterMove)
        {
            Broad b = broad.Clone() as Broad;
            Action<MoveAction> callback = m =>
            {
                synchronizeInvoke.Invoke(new CallbackDelegate(doAfterMove), new Object[] { m });
            };

            AsyncSearch(broad, depth, callback);
        }

        protected void AsyncSearch(Broad broad,int depth, Action<MoveAction> callback)
        {
            AsyncSearch(broad, depth, -MATE, MATE, callback);
        }

        ThreadExecuter threadExecuter = new ThreadExecuter();

        public void AsyncSearch(Broad broad, int depth, long alpha, long beta, Action<MoveAction> callback)
        {
            List<MoveAction> movies = GetSortedAllCanMoves(broad);
            MoveAction bestMove = null;

            if ((depth <= 0 && movies.Count > 0))
            {
                callback(movies[0]);
                return;
            }
            int taskCount = 0;

            Action<MoveAction> searchAction = moveAction =>
            {
                lock (this)
                {
                    if (bestMove == null || bestMove.Score < moveAction.Score)
                    {
                        bestMove = moveAction;
                        alpha = bestMove.Score;
                    }
                }
                if (Interlocked.Decrement(ref taskCount) == 0)
                    callback(bestMove);
            };

            SearchContext context = new SearchContext
            {
                 alpha=alpha,
                  callback= searchAction,
                  parent=this
            };

            depth--;

            foreach (MoveAction move in movies)
            {
                Interlocked.Increment(ref taskCount);
                Broad anotherBroad = broad.Clone() as Broad;
                anotherBroad.DoNextMove(move);
                SearchTask task = new SearchTask { moveAction = move, aiChessboard = broad, context = context,depth=depth };
                threadExecuter.Execute(task.Run);


            }


        }

        class SearchContext
        {
            public Action<MoveAction> callback;
            public AsyncAlphaBetaAlgorithm<Broad> parent;
            public long alpha;
        }

        class SearchTask
        {
            public MoveAction moveAction;
            public Broad aiChessboard;
            public SearchContext context;
            public int depth;

            public void CallBack(MoveAction action)
            {
                if (action != null)
                    moveAction.Score -= action.Score;
                context.callback(moveAction);
            }

            public void Run()
            {

                context.parent.AsyncSearch(aiChessboard, depth , long.MinValue, -context.alpha, CallBack);

            }
        }
    }
}
